"""
声纹采集增强版
功能：带参数校验、设备检测、音频归一化、错误处理的高可靠性录音工具
"""

import sounddevice as sd
import numpy as np
import soundfile as sf
import time
from pathlib import Path
from typing import Optional


def print_available_devices():
    """打印系统可用的音频设备列表"""
    print("可用音频设备：")
    print(sd.query_devices())


def record_sample(
        duration: float = 5.0,
        sample_rate: int = 44100,
        output_dir: str = "data/raw",
        device: Optional[int] = None,
        auto_normalize: bool = True,
        silence_threshold: float = 0.01
) -> Optional[Path]:
    """
    高可靠性音频录制函数

    参数：
    duration : float, 可选
        录音时长（秒），默认5秒，必须大于0
    sample_rate : int, 可选
        采样率（Hz），默认44100
    output_dir : str, 可选
        输出目录路径，默认"data/raw"
    device : int, 可选
        指定音频设备ID，默认None（使用系统默认设备）
    auto_normalize : bool, 可选
        自动归一化音频峰值，默认True
    silence_threshold : float, 可选
        静音检测阈值（绝对值），默认0.01

    返回：
    Path | None : 成功返回文件路径，失败返回None

    异常：
    可能抛出ValueError当输入参数无效时
    """

    # 参数有效性校验
    if duration <= 0:
        raise ValueError("录音时长必须大于0")
    if sample_rate <= 0:
        raise ValueError("采样率必须大于0")
    if not 0 <= silence_threshold <= 1.0:
        raise ValueError("静音阈值必须在0-1之间")

    try:
        # 打印录音参数
        print(f"开始录音：{duration}秒，采样率：{sample_rate}Hz，设备：{device or '默认设备'}")

        # 执行录音（使用指定数据类型）
        audio = sd.rec(
            int(duration * sample_rate),
            samplerate=sample_rate,
            channels=1,
            dtype='float32',
            device=device
        )

        # 显示录音进度
        print("录音进行中...", end='', flush=True)
        sd.wait()
        print("完成！")

        # 处理音频数据
        audio = np.squeeze(audio)  # 移除单通道的额外维度

        # 静音检测（防止麦克风故障）
        max_amplitude = np.max(np.abs(audio))
        if max_amplitude < silence_threshold:
            raise ValueError("检测到静音或音量过低，请检查麦克风")

        # 自动音量归一化
        if auto_normalize and max_amplitude > 0:
            audio /= max_amplitude  # 将峰值归一化到[-1, 1]范围

        # 创建输出目录
        output_path = Path(output_dir)
        output_path.mkdir(parents=True, exist_ok=True)

        # 生成唯一文件名（毫秒级时间戳）
        timestamp = int(time.time() * 1000)
        filename = output_path / f"sample_{timestamp}.wav"

        # 保存为16-bit PCM WAV格式
        sf.write(
            str(filename),
            audio,
            sample_rate,
            subtype='PCM_16',
            format='WAV'
        )

        print(f"成功保存录音文件：{filename}")
        return filename

    except sd.PortAudioError as pa_error:
        print(f"音频设备错误：{str(pa_error)}")
        print("请检查设备连接，可用设备列表：")
        print_available_devices()
    except Exception as e:
        print(f"录音失败：{str(e)}")
    return None


if __name__ == "__main__":
    # 示例用法
    print_available_devices()  # 显示可用设备

    # 录制参数设置
    try:
        record_sample(
            duration=10,
            sample_rate=48000,
            output_dir="data/raw/shovel",
            auto_normalize=True,
            silence_threshold=0.02
        )
    except ValueError as ve:
        print(f"参数错误：{str(ve)}")